<?php

namespace app\common\lib;

use app\common\cachemodel\MentalQuestionModel;
use app\common\lib\exception\ApiException;
use think\Log;
use think\response\Json;

class MentalTestUtil
{

    private static $LOG_PRE = '壹心理工具类：';

    /**
     * 生成签名
     * @param array $reqParamArray 请求参数
     * @return string 签名
     */
    public static function generateSignature($reqParamArray = [])
    {
        // 1、 检验是否是数组
        if (!is_array($reqParamArray))
        {
            Log::write(self::$LOG_PRE . 'generateSignature 生成签名方法，参数类型错误，应该为数组', 'log');
            return "";   //不是数组返回空字符串
        }
        //增加渠道id
        array_unshift($reqParamArray, config('mental_test.channel_id'));
        // 请求参数数组追加 企业密钥
        $reqParamArray[] = config('mental_test.company_secret');

        // 2、对数组进行排序
        sort($reqParamArray, 2);
        // 3、对排序后的数组遍历 拼接字符串
        $str = "";
        foreach ($reqParamArray as $value)
        {
            $str .= $value;
        }
        // 4、进行sha1加密
        $sha1Str = sha1($str);
        //5、得到最后签名
        return $sha1Str . "";
    }

    /**
     * 请求壹心理支付接口
     * @param int $uid 用户id
     * @param string $orderNo 订单号
     * @param int $scalePoolId 解锁id
     * @param int $tradeType 支付方式：2=>支付宝,1=>微信支付
     * @return array
     * @throws ApiException
     */
    public static function pay(int $uid, string $orderNo, int $scalePoolId, int $tradeType): array
    {
        //支付方式转换 //2=>支付宝,1=>微信支付
        if ($tradeType === 1)
        {//微信支付
            $tradeType = 17;
        } else
        {//支付宝支付
            $tradeType = 11;
        }
//        ## 1、购买及支付单条测评
//
//        * /payScale
//
//##### 请求参数
//    |        | 必选    |  类型及范围  |说明   |
//| --------   | -----:   | :----: |:----: |
//| openUserId  | true      |   string    |	合作单位用户唯一标识。|
//| orderNo  | true      |   string    |	合作单位订单号。|
//| scalePoolId  | true      |   int    |	测评id。|
//| tradeType  | true      |   int    |	交易类型： 17=微信APP支付。|

        $signature = self::generateSignature([$uid, $orderNo, $scalePoolId, $tradeType]);
        $url = config('mental_test.url_pay') . '/lingxi/service/payScale?channelId=' . config('mental_test.channel_id') . '&openUserId=' . $uid . '&orderNo=' . $orderNo . '&scalePoolId=' . $scalePoolId . '&tradeType=' . $tradeType . '&signature=' . $signature;
        $result = Util::curlRequest('GET', $url);
        $result = json_decode($result, true);

        if (!$result)
        {
            Log::write(self::$LOG_PRE . '支付返回结果为nil【uid=' . $uid . ',orderNo=' . $orderNo . ',scalePoolId=' . $scalePoolId . ',tradeType=' . $tradeType . '】', 'error', true);
            throw new ApiException('下单失败,请重新操作');
        }

        if (isset($result['code']) && (int)$result['code'] !== 1)
        {//失败，返回信息
            Log::write(self::$LOG_PRE . '支付返回结果code不为1，结果:' . json_encode($result, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . '【uid=' . $uid . ',orderNo=' . $orderNo . ',scalePoolId=' . $scalePoolId . ',tradeType=' . $tradeType . '】', 'error', true);
            throw new ApiException($result['msg']);
        }

        //成功，那么拼接客户端需要的字段
        if ($tradeType === 17)
        {//微信支付
            $data_yixinli = json_decode($result['data']['payInfo'], true);
            $data_yixinli['trade_type'] = 1;//trade_type 1：微信  2：支付宝
            $data = $data_yixinli;
        } else
        {//支付宝支付
            $data['trade_type'] = 2;//trade_type 1：微信  2：支付宝
            $data['pay_url'] = $result['data']['payInfo'];
        }
        $data['order_id'] = $orderNo;
        return $data;
    }


    /**
     * 请求壹心理下单接口（免费问题）
     * @param int $uid 用户id
     * @param string $orderNo 订单号
     * @param int $scalePoolId 解锁id
     * @return string
     * @throws ApiException 接口文档：https://code.aliyun.com/yixinli-public/ceping-api/wikis/ceping-api
     */
    public static function payFree(int $uid, string $orderNo, int $scalePoolId): string
    {

//        3、购买单条测评（支付成功后调用）
//    /buyScale
//购买测评
//
//请求参数
//必选	类型及范围
//channelId	true	int	壹心理分配给 第三方合作伙伴的 渠道 ID。
//openUserId	true	string	第三方接入企业的 用户唯一ID。
//scalePoolId	true	int	测评唯一标识，量表ID。
//orderId	true	string	第三方企业支付环节的 唯一订单号，方便对账统计
//sourceName	false	string	跟踪标识，第三方可选给订单加上自定义标识，后续在壹心理订单记录中搜索这些标识
//signature	true	string	签名信息，用于双方接口参数加密验签。
//请求方法
//GET
//
//调用样例
///lingxi/service/buyScale?channelId=238&openUserId=weijieOpenUserId&scalePoolId=75&orderId=weijieTestId&signature=9f4651da5b93dd173d19167c8f381bb1dbd2902f
//返回结果
//JSON示例
//{
//    "code": "1",
//    "msg": "请求接口成功",
//    "data": {
//    "channelId": 238,
//        "scalePoolId": 75,
//        "accountId": 1424275,
//        "dataUrl": "http://cpapi-box3.xinli001.com/login?username=8bsb-urkg-9bfc&password=330596&requestLoginSource=lxSys"
//    }
//}
//返回字段说明
//返回值字段	字段类型	字段说明
//code	string	公共返回码。
//msg	string	公共返回码 描述信息。
//data	jsonObject	数据Json对象。
//channelId	int	渠道id。
//scalePoolId	int	测评id
//accountId	int	测试账号id
//dataUrl	string	跳转答题地址


        $signature = self::generateSignature([$uid, $orderNo, $scalePoolId]);
        $url = config('mental_test.url_pay') . '/lingxi/service/buyScale?channelId=' . config('mental_test.channel_id') . '&openUserId=' . $uid . '&orderId=' . $orderNo . '&scalePoolId=' . $scalePoolId . '&signature=' . $signature;
        $result = Util::curlRequest('GET', $url);
        $result = json_decode($result, true);

        if (!$result)
        {
            Log::write(self::$LOG_PRE . '免费测评下单，返回结果为nil【uid=' . $uid . ',orderNo=' . $orderNo . ',scalePoolId=' . $scalePoolId . '】', 'error', true);
            throw new ApiException('下单失败,请重新操作');
        }

        if (isset($result['code']) && (int)$result['code'] !== 1)
        {//失败，返回信息
            Log::write(self::$LOG_PRE . '免费测评下单，返回结果code不为1，结果:' . json_encode($result, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . '【uid=' . $uid . ',orderNo=' . $orderNo . ',scalePoolId=' . $scalePoolId . '】', 'error', true);
            throw new ApiException($result['msg']);
        }

        return $result['data']['accountId'];
    }

    /**
     * 查询订单状态
     * @param string $orderNo 订单号
     * @return array
     */
    public static function queryOrder(string $orderNo)
    {

//## 2、查询订单状态
//        *  /queryOrder
//##### 请求参数
//    |        | 必选    |  类型及范围  |   |
//| --------   | -----:   | :----: |:----: |
//| orderNo  | false      |   string    |	订单号， 传了订单号就不用传交易号|
//##### 请求方法
//GET

        $signature = self::generateSignature([$orderNo]);
        $url = config('mental_test.url_pay') . '/lingxi/service/queryOrder?channelId=' . config('mental_test.channel_id') . '&orderNo=' . $orderNo . '&signature=' . $signature;
        $result = Util::curlRequest('GET', $url);
        $result = json_decode($result, true);


        if ($result && isset($result['code']) && (int)$result['code'] !== 1)
        {//失败，返回信息
            Log::write(self::$LOG_PRE . '查询订单状态：$orderNo=' . $orderNo . '$result=' . json_encode($result, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), 'error', true);
            return [
                'is_sucess' => false,
                'msg' => $result['msg'],
                'account_id' => ''
            ];
        }

        if (!isset($result['data']['accountId']))
        {
            Log::write(self::$LOG_PRE . '查询订单状态[' . $orderNo . ']accountId 为空,' . '$result=' . json_encode($result, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), 'error', true);
            return [
                'is_sucess' => false,
                'msg' => $result['msg'],
                'account_id' => ''
            ];
        }

        return [
            'is_sucess' => true,
            'msg' => $result['msg'],
            'account_id' => $result['data']['accountId']
        ];
    }

    /**
     * 查询订单状态
     * @param $uid
     * @param array $answers
     * @return array
     */
    public static function submitAnswers($uid = 0, $answers = []): array
    {
        if (!$answers)
        {
            return [false, ''];
        }

//        $uid = 112204918;
//## 2、生成报告(批量提交答案)
//        * /api/v2/batchCommitAllAnswers
//    ---
//#####生成报告数据, 做完模块题目最后 点击查看报告时 调用。
//##### 请求参数
//|        | 必选    |  类型及范围  |说明   |
//| --------   | -----:   | :----: |:----: |
//| accountId  | true      |   int    |	用户测评账号id。|
//| answers  | true      |   jsonArray    |	答题内容集合。|
//||||
//| questionnaireId  | true      |   int    |	问卷id	。|
//| questionId  | true      |   int    |	问题id	。|
//| optionId  | true      |   int    |	选项id	。|
//| type  | true      |   int    |	题目类型：0单选题，1游标题，2文字题。|
//| content  | false      |   string    |	文本题内容，长度不限制。|
//| score  | false      |   int    |	游标题得分。|
//
//##### 请求方法
//POST

        $reqParamArray = [];
        $reqParamArray[] = $uid;
        foreach ($answers as $k => $v)
        {
            $reqParamArray[] = $v;
        }
        $signature = self::generateSignature($reqParamArray);

        $url = config('mental_test.url_answer') . '/cp/service/api/v2/batchCommitAllAnswers';
        $answers['accountId'] = $uid;
        $answers['channelId'] = config('mental_test.channel_id');
        $answers['signature'] = $signature;

        $result = Util::curlRequest('POST', $url, http_build_query($answers), ['Content-Type:application/x-www-form-urlencoded']);
        $result = json_decode($result, true);
//        Log::write(self::$LOG_PRE . '提交答案返回结果：(' . json_encode($result) . ')', 'error', true);

        if ($result && isset($result['code']) && (int)$result['code'] !== 1)
        {//失败，返回信息
            Log::write(self::$LOG_PRE . '提交答案异常(' . $result['msg'] . ')', 'error', true);
            return [false, ''];
        }

        if (!isset($result['data']['redirectUrl']))
        {
            if (isset($result['data']['code']) && (int)$result['data']['code'] === 40011)
            {//测试已完成的code
                return self::getReportUrl($uid);
            }
            Log::write(self::$LOG_PRE . '提交答案异常(redirectUrl不存在)，返回结果：【' . json_encode($result, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . '】', 'error', true);
            return [false, ''];
        }

        return [true, self::decodeReportUrl($result['data']['redirectUrl'])];
    }


    /**
     * 获取报告访问地址
     * @param int $accountId 壹心理返回的账号
     * @return array
     */
    public static function getReportUrl($accountId = 0): array
    {
        if (!$accountId)
        {
            return [false, ''];
        }

//## 3、获取报告访问地址：
//        * /api/v2/getReportUrl
//##### 请求参数
//|        | 必选    |  类型及范围  |说明   |
//| --------   | -----:   | :----: |:----: |
//| accountId  | true      |   int    |	用户测评账号id。|
//##### 请求方法
//POST
//##### 调用样例
///api/v2/getReportUrl?accountId=282
//##### 返回结果
//##### JSON示例
//* 成功获取到报告的情况
//{
//    "code":"1",
//    "msg":"请求接口成功",
//    "data":{
//    "redirectUrl": "https://hd.xinli001wx.com/cp/index.html?init=29#/newReport/?accountId=3701720&channelId=1&uid=WUMv4qqfh37mRcN8fn4g&enterFrom=mine&tabModuleId=525&userKey=16840474969852313622&isEnded=false&isShowAd=0&isNewVersion=0&scalePoolId=524"
//    }
//}
//##### 返回字段说明
//|    返回值字段    | 字段类型    |  字段说明
//    | --------   | -----:   | :----: |
//|code| string  |	公共返回码。|
//|msg |string|	公共返回码 描述信息。
//    |data |jsonObject|	数据Json对象。
//    |algorithmType |int| 代表新测评
//    |redirectUrl |string| 提交成功后前端需要跳转这个地址

        $signature = self::generateSignature([$accountId]);
        $url = config('mental_test.url_answer') . '/cp/service/api/v2/getReportUrl';
        $post_data['accountId'] = $accountId;
        $post_data['channelId'] = config('mental_test.channel_id');
        $post_data['signature'] = $signature;

        //form
        $result = Util::curlRequest('POST', $url, http_build_query($post_data), ['Content-Type:application/x-www-form-urlencoded']);
        //json
//        $result = Util::curlRequest('POST', $url, $post_data);
        $result = json_decode($result, true);
//        Log::write(self::$LOG_PRE . '获取报告访问地址 返回结果：(' . json_encode($result) . ')', 'error', true);

        if ($result && isset($result['code']) && (int)$result['code'] !== 1)
        {//失败，返回信息
            Log::write(self::$LOG_PRE . '获取报告访问地址 异常(' . $result['msg'] . ')', 'error', true);
            return [false, ''];
        }

        if (!isset($result['data']['redirectUrl']))
        {
            Log::write(self::$LOG_PRE . '获取报告访问地址 异常(redirectUrl不存在)', 'error', true);
            return [false, ''];
        }
        return [true, self::decodeReportUrl($result['data']['redirectUrl'])];
    }


    /**
     * 获取用户的测评列表（线上不用，用来测试壹心理支付是否成功）
     * @param int $uid 用户id
     * @param int $state 完成状态，0 未完成 1已完成，不传默认返回所有数据。
     * @return Json
     */
    public static function getUserQuestions(int $uid, int $state): Json
    {

//        4、获取 我的测评列表 (已购买的测评数据) 接口
//    /getMyComboScaleData
//返回用户已购买的测评列表
//
//请求参数
//必选	类型及范围
//channelId	true	int	壹心理分配给 第三方合作伙伴的 渠道 ID。
//openUserId	true	string	第三方接入企业的 用户唯一ID。
//state	true	int	完成状态，0 未完成 1已完成，不传默认返回所有数据。
//signature	true	string	签名信息，用于双方接口参数加密验签。

        $signature = self::generateSignature([$uid, $state]);
        $url = config('mental_test.url_answer') . '/lingxi/service/getMyComboScaleData?channelId=' . config('mental_test.channel_id') . '&openUserId=' . $uid . '&state=' . $state . '&signature=' . $signature;
        $result = Util::curlRequest('GET', $url);
        $result = json_decode($result, true);


        if ($result && isset($result['code']) && (int)$result['code'] !== 1)
        {//失败，返回信息
            return show(config('code.error'), $result['msg']);
        }

        return show(config('code.success'), '请求成功', $result);
    }


    /**
     * 将ascii码 替换为相应的字符串
     * @param $url
     * @return string
     */
    private static function decodeReportUrl($url): string
    {
        return str_replace(array('\u0026', '\u003d'), array('&', '='), $url);
    }


    /**
     * 校验子类
     * @param $question
     * @param int $child_id
     * @return array
     */
    public static function validChildId($question, $child_id = 0): array
    {
        $question_child_detail = null;
        if (!$question)
        {
            return [false, $question_child_detail];
        }

        if (!$child_id)
        {
            return [true, $question_child_detail];
        }

        $child_scales = json_decode($question['child_scales'], true);

        $is_in = false;
        if (count($child_scales) > 0)
        {
            foreach ($child_scales as $k => $v)
            {
                if ((int)$v['scalePoolId'] === (int)$child_id)
                {
                    $is_in = true;
                }
            }
        } else if ((int)$question['id'] === $child_id)
        {
            $is_in = true;
        }
        if (!$is_in)
        {
            return [false, $question_child_detail];
        }

        //如果child_id不为空，那么查询，详情是否存在
        try
        {
            $question_child_detail = (new MentalQuestionModel())->getQuestionDetailById($question['id'], [], $child_id);
            if (!$question_child_detail)
            {
                $is_in = false;
            } else
            {
                $is_in = true;
            }
        }
        catch (ApiException $e)
        {
            Log::write('validChildId 方法：' . $e->getMessage() . "；错误文件「{$e->getFile()}」错误行数「{$e->getLine()}」", 'error', true);
            $is_in = false;
        }


        return [$is_in, $question_child_detail];
    }
}
